#ifndef INTERPRETER_H
#define INTERPRETER_H

#include <iostream>
#include <map>
#include <stack>
#include <string>

class Expression {
public:
  virtual int Interpreter(std::map<std::string, int>& var) = 0;
};

class VarExpression : public Expression {
public:
  VarExpression(const std::string& key) : key_(key) {}

  int Interpreter(std::map<std::string, int>& var) {
    return var[key_];
  }

private:
  std::string key_;
};

class SymbolExpression : public Expression {
public:
  SymbolExpression(Expression* left, Expression* right) : left_(left), right_(right) {}

public:
  Expression* left_;
  Expression* right_;
};

class SubExpression : public SymbolExpression {
public:
  SubExpression(Expression* left, Expression* right) : SymbolExpression(left, right) {}

  int Interpreter(std::map<std::string, int>& var) {
    return left_->Interpreter(var) - right_->Interpreter(var);
  }
};

class AddExpression : public SymbolExpression {
public:
  AddExpression(Expression* left, Expression* right) : SymbolExpression(left, right) {}

  int Interpreter(std::map<std::string, int>& var) {
    return left_->Interpreter(var) + right_->Interpreter(var);
  }
};

class Calculator {
public:
  Calculator(std::string& expression) {
    std::stack<Expression*> expression_stack;
    char c;
    Expression* left;
    Expression* right;
    Expression* add_expression;
    Expression* sub_expression;
    for (int i = 0; i < expression.length(); i++) {
      c = expression[i];
      switch(c) {
        case '+' :
          left = expression_stack.top();
          expression_stack.pop();
          right = new VarExpression(std::string(1, expression[++i]));
          add_expression = new AddExpression(left, right);
          expression_stack.push(add_expression);
          break;
        case '-' :
          left = expression_stack.top();
          expression_stack.pop();
          right = new VarExpression(std::string(1, expression[++i]));
          sub_expression = new SubExpression(left, right);
          expression_stack.push(sub_expression);
          break;
        default:
          expression_stack.push(new VarExpression(std::string(1, c)));
          break;
      }
    }

    expression_ = expression_stack.top();
    expression_stack.pop();
  }

  int Run(std::map<std::string, int>& var) {
    return expression_->Interpreter(var);
  }

private:
  Expression* expression_;
};

#endif // INTERPRETER_H
